{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# python notebook for Make Your Own Neural Network\n",
    "# code for a 3-layer neural network, and code for learning the MNIST dataset\n",
    "# this version asks the network what the image should be, given a label\n",
    "# (c) Tariq Rashid, 2016\n",
    "# license is GPLv2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy\n",
    "# scipy.special for the sigmoid function expit(), and its inverse logit()\n",
    "import scipy.special\n",
    "# library for plotting arrays\n",
    "import matplotlib.pyplot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# neural network class definition\n",
    "class neuralNetwork:\n",
    "    \n",
    "    \n",
    "    # initialise the neural network\n",
    "    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):\n",
    "        # set number of nodes in each input, hidden, output layer\n",
    "        self.inodes = inputnodes\n",
    "        self.hnodes = hiddennodes\n",
    "        self.onodes = outputnodes\n",
    "        \n",
    "        # link weight matrices, wih and who\n",
    "        # weights inside the arrays are w_i_j, where link is from node i to node j in the next layer\n",
    "        # w11 w21\n",
    "        # w12 w22 etc \n",
    "        self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))\n",
    "        self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))\n",
    "\n",
    "        # learning rate\n",
    "        self.lr = learningrate\n",
    "        \n",
    "        # activation function is the sigmoid function\n",
    "        self.activation_function = lambda x: scipy.special.expit(x)\n",
    "        self.inverse_activation_function = lambda x: scipy.special.logit(x)\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # train the neural network\n",
    "    def train(self, inputs_list, targets_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        targets = numpy.array(targets_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        # output layer error is the (target - actual)\n",
    "        output_errors = targets - final_outputs\n",
    "        # hidden layer error is the output_errors, split by weights, recombined at hidden nodes\n",
    "        hidden_errors = numpy.dot(self.who.T, output_errors) \n",
    "        \n",
    "        # update the weights for the links between the hidden and output layers\n",
    "        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))\n",
    "        \n",
    "        # update the weights for the links between the input and hidden layers\n",
    "        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # query the neural network\n",
    "    def query(self, inputs_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        return final_outputs\n",
    "    \n",
    "    \n",
    "    # backquery the neural network\n",
    "    # we'll use the same termnimology to each item, \n",
    "    # eg target are the values at the right of the network, albeit used as input\n",
    "    # eg hidden_output is the signal to the right of the middle nodes\n",
    "    def backquery(self, targets_list):\n",
    "        # transpose the targets list to a vertical array\n",
    "        final_outputs = numpy.array(targets_list, ndmin=2).T\n",
    "        \n",
    "        # calculate the signal into the final output layer\n",
    "        final_inputs = self.inverse_activation_function(final_outputs)\n",
    "\n",
    "        # calculate the signal out of the hidden layer\n",
    "        hidden_outputs = numpy.dot(self.who.T, final_inputs)\n",
    "        # scale them back to 0.01 to .99\n",
    "        hidden_outputs -= numpy.min(hidden_outputs)\n",
    "        hidden_outputs /= numpy.max(hidden_outputs)\n",
    "        hidden_outputs *= 0.98\n",
    "        hidden_outputs += 0.01\n",
    "        \n",
    "        # calculate the signal into the hidden layer\n",
    "        hidden_inputs = self.inverse_activation_function(hidden_outputs)\n",
    "        \n",
    "        # calculate the signal out of the input layer\n",
    "        inputs = numpy.dot(self.wih.T, hidden_inputs)\n",
    "        # scale them back to 0.01 to .99\n",
    "        inputs -= numpy.min(inputs)\n",
    "        inputs /= numpy.max(inputs)\n",
    "        inputs *= 0.98\n",
    "        inputs += 0.01\n",
    "        \n",
    "        return inputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# number of input, hidden and output nodes\n",
    "input_nodes = 784\n",
    "hidden_nodes = 200\n",
    "output_nodes = 10\n",
    "\n",
    "# learning rate\n",
    "learning_rate = 0.1\n",
    "\n",
    "# create instance of neural network\n",
    "n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the mnist training data CSV file into a list\n",
    "training_data_file = open(\"mnist_dataset/mnist_train.csv\", 'r')\n",
    "training_data_list = training_data_file.readlines()\n",
    "training_data_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# train the neural network\n",
    "\n",
    "# epochs is the number of times the training data set is used for training\n",
    "epochs = 5\n",
    "\n",
    "for e in range(epochs):\n",
    "    # go through all records in the training data set\n",
    "    for record in training_data_list:\n",
    "        # split the record by the ',' commas\n",
    "        all_values = record.split(',')\n",
    "        # scale and shift the inputs\n",
    "        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01\n",
    "        # create the target output values (all 0.01, except the desired label which is 0.99)\n",
    "        targets = numpy.zeros(output_nodes) + 0.01\n",
    "        # all_values[0] is the target label for this record\n",
    "        targets[int(all_values[0])] = 0.99\n",
    "        n.train(inputs, targets)\n",
    "        pass\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# load the mnist test data CSV file into a list\n",
    "test_data_file = open(\"mnist_dataset/mnist_test.csv\", 'r')\n",
    "test_data_list = test_data_file.readlines()\n",
    "test_data_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# test the neural network\n",
    "\n",
    "# scorecard for how well the network performs, initially empty\n",
    "scorecard = []\n",
    "\n",
    "# go through all the records in the test data set\n",
    "for record in test_data_list:\n",
    "    # split the record by the ',' commas\n",
    "    all_values = record.split(',')\n",
    "    # correct answer is first value\n",
    "    correct_label = int(all_values[0])\n",
    "    # scale and shift the inputs\n",
    "    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01\n",
    "    # query the network\n",
    "    outputs = n.query(inputs)\n",
    "    # the index of the highest value corresponds to the label\n",
    "    label = numpy.argmax(outputs)\n",
    "    # append correct or incorrect to list\n",
    "    if (label == correct_label):\n",
    "        # network's answer matches correct answer, add 1 to scorecard\n",
    "        scorecard.append(1)\n",
    "    else:\n",
    "        # network's answer doesn't match correct answer, add 0 to scorecard\n",
    "        scorecard.append(0)\n",
    "        pass\n",
    "    \n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "performance =  0.9711\n"
     ]
    }
   ],
   "source": [
    "# calculate the performance score, the fraction of correct answers\n",
    "scorecard_array = numpy.asarray(scorecard)\n",
    "print (\"performance = \", scorecard_array.sum() / scorecard_array.size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.99 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x12607b230>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# run the network backwards, given a label, see what image it produces\n",
    "\n",
    "# label to test\n",
    "label = 0\n",
    "# create the output signals for this label\n",
    "targets = numpy.zeros(output_nodes) + 0.01\n",
    "# all_values[0] is the target label for this record\n",
    "targets[label] = 0.99\n",
    "print(targets)\n",
    "\n",
    "# get image data\n",
    "image_data = n.backquery(targets)\n",
    "\n",
    "# plot image data\n",
    "matplotlib.pyplot.imshow(image_data.reshape(28,28), cmap='Greys', interpolation='None')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
